#include "gd32f470vet6_bsp.h"

/* SCHEDULER */
volatile uint32_t uwTick = 0;

Task_t schedul_task[] =
{
    {Usart0Task,    5, 0},
    {Usart1Task,    5, 0},
    {BtnTask   ,    5, 0},
    {AdcTask   ,  200, 0},
    {LedTask   ,    1, 0},
    {RtcTask   , 1000, 0},
    {OledTask  ,  200, 0}
};

uint8_t task_num = sizeof(schedul_task) / sizeof(Task_t);

/* LED */
uint8_t ucLed[LED_NUM] = {0};

void LedDisp(uint8_t *ucLed)
{
    uint8_t temp = 0x00;
    static uint8_t temp_old = 0xff;
    for (int i = 0; i < LED_NUM; i++)  { if (ucLed[i]) temp |= (0x01 << i); }

    if (temp_old != temp)
    {
        gpio_bit_write(LED_GPIO_PORT, LED1_PIN, temp & 0x01 ? SET : RESET);
        gpio_bit_write(LED_GPIO_PORT, LED2_PIN, temp & 0x02 ? SET : RESET);
        gpio_bit_write(LED_GPIO_PORT, LED3_PIN, temp & 0x04 ? SET : RESET);
        gpio_bit_write(LED_GPIO_PORT, LED4_PIN, temp & 0x08 ? SET : RESET);
        gpio_bit_write(LED_GPIO_PORT, LED5_PIN, temp & 0x10 ? SET : RESET);
        gpio_bit_write(LED_GPIO_PORT, LED6_PIN, temp & 0x20 ? SET : RESET);

        temp_old = temp;
    }
}

static void LedPeriphInit(void)
{
    rcu_periph_clock_enable(LED_GPIO_CLK);

    gpio_mode_set(LED_GPIO_PORT, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, LED1_PIN | LED2_PIN | LED3_PIN | LED4_PIN | LED5_PIN | LED6_PIN);
    gpio_output_options_set(LED_GPIO_PORT, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, LED1_PIN | LED2_PIN | LED3_PIN | LED4_PIN | LED5_PIN | LED6_PIN);

    GPIO_BC(LED_GPIO_PORT) = LED1_PIN | LED2_PIN | LED3_PIN | LED4_PIN | LED5_PIN | LED6_PIN;
}

/* BTN */
// 定义按键参数
static const ebtn_btn_param_t defaul_ebtn_param = EBTN_PARAMS_INIT(
    10,  // time_debounce: 按下消抖时间 (ms), 一般为 20ms
    10,  // time_debounce_release: 释放消抖时间 (ms), 一般为 20ms
    20,  // time_click_pressed_min: 按下至少多长时间算有效点击 (ms)
    450, // time_click_pressed_max: 按下最多多长时间算有效点击 (ms)
    0, // time_click_multi_max: 多击之间最大间隔时间 (ms)
    500, // time_keepalive_period: 长按触发周期 (ms), 0表示不触发长按事件 (注意长按周期应大于 time_click_pressed_max)
    5    // max_consecutive: 最大连续点击次数, 达到次数后立即发送 ONCLICK 事件
);

// 注册按键ID
static ebtn_btn_t btns[] = {
    EBTN_BUTTON_INIT(USER_BUTTON_1, &defaul_ebtn_param),
    EBTN_BUTTON_INIT(USER_BUTTON_2, &defaul_ebtn_param),
    EBTN_BUTTON_INIT(USER_BUTTON_3, &defaul_ebtn_param),
    EBTN_BUTTON_INIT(USER_BUTTON_4, &defaul_ebtn_param),
    EBTN_BUTTON_INIT(USER_BUTTON_5, &defaul_ebtn_param),
    EBTN_BUTTON_INIT(USER_BUTTON_6, &defaul_ebtn_param),
};

// 注册组合按键ID
static ebtn_btn_combo_t btns_combo[] = {
    EBTN_BUTTON_COMBO_INIT(USER_BUTTON_COMBO_1, &defaul_ebtn_param),
    EBTN_BUTTON_COMBO_INIT(USER_BUTTON_COMBO_2, &defaul_ebtn_param),
};

// 事件循环函数：获取按键状态
static uint8_t BtnGetState(struct ebtn_btn *btn)
{
    uint8_t state = 0;

    switch (btn -> key_id)
    {
        case USER_BUTTON_1:
            state = (gpio_input_bit_get(GPIOB, BTN1_PIN) == RESET);
            break;

        case USER_BUTTON_2:
            state = (gpio_input_bit_get(GPIOE, BTN2_PIN) == RESET);
            break;

        case USER_BUTTON_3:
            state = (gpio_input_bit_get(GPIOE, BTN3_PIN) == RESET);
            break;

        case USER_BUTTON_4:
            state = (gpio_input_bit_get(GPIOE, BTN4_PIN) == RESET);
            break;

        case USER_BUTTON_5:
            state = (gpio_input_bit_get(GPIOE, BTN5_PIN) == RESET);
            break;

        case USER_BUTTON_6:
            state = (gpio_input_bit_get(GPIOE, BTN6_PIN) == RESET);
            break;
    }

    return state;
}

static void BtnPeriphInit(void)
{
    rcu_periph_clock_enable(BTNB_GPIO_CLK);
    rcu_periph_clock_enable(BTNE_GPIO_CLK);
    
    gpio_mode_set(BTNB_GPIO_PORT, GPIO_MODE_INPUT, GPIO_PUPD_NONE, BTN1_PIN);
    gpio_mode_set(BTNE_GPIO_PORT, GPIO_MODE_INPUT, GPIO_PUPD_NONE, BTN2_PIN | BTN3_PIN | BTN4_PIN | BTN5_PIN | BTN6_PIN);

    ebtn_init(btns, EBTN_ARRAY_SIZE(btns), btns_combo, EBTN_ARRAY_SIZE(btns_combo), BtnGetState, BtnEventCallback);

    // 编辑组合按键
    ebtn_combo_btn_add_btn(&btns_combo[0], USER_BUTTON_1);
    ebtn_combo_btn_add_btn(&btns_combo[0], USER_BUTTON_2);

    // 启用组合键优先模式
    ebtn_set_config(EBTN_CFG_COMBO_PRIORITY);

    // 设置组合键抑制阈值
    ebtn_set_combo_suppress_threshold(300);
}

/* ADC */
uint16_t adc0_value[ADC0_BUFFER_SIZE] = {0};
float adc0_voltage = 0.0f;

static void AdcDmaInit(void)
{
    dma_single_data_parameter_struct dma_single_data_parameter;

    rcu_periph_clock_enable(RCU_DMA1);

    dma_deinit(DMA1, DMA_CH0);

    dma_single_data_parameter.periph_addr         = ADC0_DATA_ADDRESS;
    dma_single_data_parameter.periph_inc          = DMA_PERIPH_INCREASE_DISABLE;
    dma_single_data_parameter.memory0_addr        = (uint32_t)(adc0_value);
    dma_single_data_parameter.memory_inc          = DMA_MEMORY_INCREASE_ENABLE;
    dma_single_data_parameter.periph_memory_width = DMA_PERIPH_WIDTH_16BIT;
    dma_single_data_parameter.direction           = DMA_PERIPH_TO_MEMORY;
    dma_single_data_parameter.number              = ADC0_BUFFER_SIZE;
    dma_single_data_parameter.priority            = DMA_PRIORITY_HIGH;
    dma_single_data_mode_init(DMA1, DMA_CH0, &dma_single_data_parameter);
    
    dma_circulation_enable(DMA1, DMA_CH0);
    dma_channel_subperipheral_select(DMA1, DMA_CH0, DMA_SUBPERI0);
    dma_channel_enable(DMA1, DMA_CH0);
}

static void AdcPeriphInit(void)
{
    rcu_periph_clock_enable(ADC0_GPIO_CLK);
    rcu_periph_clock_enable(RCU_ADC0);

    adc_clock_config(ADC_ADCCK_PCLK2_DIV8);
    
    gpio_mode_set(ADC0_GPIO_PORT, GPIO_MODE_ANALOG, GPIO_PUPD_NONE, ADC0_GPIO_PIN);
    
    AdcDmaInit();

    adc_sync_mode_config(ADC_SYNC_MODE_INDEPENDENT);
    adc_special_function_config(ADC0, ADC_CONTINUOUS_MODE, ENABLE);
    adc_special_function_config(ADC0, ADC_SCAN_MODE, ENABLE);
    adc_data_alignment_config(ADC0, ADC_DATAALIGN_RIGHT);
    adc_channel_length_config(ADC0, ADC_ROUTINE_CHANNEL, 1);
    adc_routine_channel_config(ADC0, 0, ADC_CHANNEL_10, ADC_SAMPLETIME_15);
    adc_external_trigger_source_config(ADC0, ADC_ROUTINE_CHANNEL, ADC_EXTTRIG_ROUTINE_T0_CH0); 
    adc_external_trigger_config(ADC0, ADC_ROUTINE_CHANNEL, EXTERNAL_TRIGGER_DISABLE);

    adc_dma_request_after_last_enable(ADC0);
    adc_dma_mode_enable(ADC0);

    adc_enable(ADC0);
    delay_1ms(1);
    adc_calibration_enable(ADC0);

    adc_software_trigger_enable(ADC0, ADC_ROUTINE_CHANNEL);
}

/* USART0 */
uint8_t usart0_rx_buffer_dma[USART0_BUFFER_SIZE]  = {0};
uint8_t usart0_rx_buffer_proc[USART0_BUFFER_SIZE] = {0};

volatile uint8_t usart0_rx_flag = 0;

static void Usart0DmaInit(void)
{
    dma_single_data_parameter_struct dma_init_para;

    rcu_periph_clock_enable(RCU_DMA1);

    dma_deinit(DMA1, DMA_CH2);
    dma_init_para.direction           = DMA_PERIPH_TO_MEMORY;
    dma_init_para.memory0_addr        = (uint32_t)usart0_rx_buffer_dma;
    dma_init_para.memory_inc          = DMA_MEMORY_INCREASE_ENABLE;
    dma_init_para.number              = USART0_BUFFER_SIZE;
    dma_init_para.periph_addr         = USART0_DATA_ADDRESS;
    dma_init_para.periph_inc          = DMA_PERIPH_INCREASE_DISABLE;
    dma_init_para.periph_memory_width = DMA_PERIPH_WIDTH_8BIT;
    dma_init_para.priority            = DMA_PRIORITY_ULTRA_HIGH;
    dma_single_data_mode_init(DMA1, DMA_CH2, &dma_init_para);

    dma_circulation_disable(DMA1, DMA_CH2);
    dma_channel_subperipheral_select(DMA1, DMA_CH2, DMA_SUBPERI4);
    dma_channel_enable(DMA1, DMA_CH2);
}

static void Usart0PeriphInit(void)
{
    rcu_periph_clock_enable(USART0_GPIO_CLK);
    rcu_periph_clock_enable(RCU_USART0);

    gpio_af_set(USART0_GPIO_PORT, GPIO_AF_7, USART0_TX_PIN);
    gpio_af_set(USART0_GPIO_PORT, GPIO_AF_7, USART0_RX_PIN);

    gpio_mode_set(USART0_GPIO_PORT, GPIO_MODE_AF, GPIO_PUPD_PULLUP, USART0_TX_PIN);
    gpio_output_options_set(USART0_GPIO_PORT, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, USART0_TX_PIN);
    gpio_mode_set(USART0_GPIO_PORT, GPIO_MODE_AF, GPIO_PUPD_PULLUP, USART0_RX_PIN);
    gpio_output_options_set(USART0_GPIO_PORT, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, USART0_RX_PIN);

    usart_deinit(USART0);
    usart_baudrate_set(USART0, USART0_BAUDRATE);
    usart_transmit_config(USART0, USART_TRANSMIT_ENABLE);
    usart_receive_config(USART0, USART_RECEIVE_ENABLE);
    usart_dma_receive_config(USART0, USART_RECEIVE_DMA_ENABLE);
    usart_enable(USART0);

    Usart0DmaInit();

    nvic_irq_enable(USART0_IRQn, 0, 0);
    usart_interrupt_enable(USART0, USART_INT_IDLE);
}

uint32_t Usart0Printf(const char *format, ...)
{
	char usart0_tx_buffer[USART0_BUFFER_SIZE];
	va_list arg;
	int len;

	va_start(arg, format);
	len = vsnprintf(usart0_tx_buffer, sizeof(usart0_tx_buffer), format, arg);
	va_end(arg);

	for (uint16_t i = 0; i < len; i++)
    {
        usart_data_transmit(USART0, usart0_tx_buffer[i]);

        uint32_t timeout_ms = uwTick;
        while (RESET == usart_flag_get(USART0, USART_FLAG_TBE)) 
        {
            if ((uwTick - timeout_ms) > USART0_TIMEOUT_MS) 
            {
                return i;  // 返回已发送字节数
            }
        }
    }

	return len;
}

/* USART1 */
uint8_t usart1_rx_buffer_dma[USART1_BUFFER_SIZE]  = {0};
uint8_t usart1_rx_buffer_proc[USART1_BUFFER_SIZE] = {0};

volatile uint8_t usart1_rx_flag = 0;

static void Rs485TxMode(void)
{
    gpio_bit_set(USART1_GPIO_PORT, RS485_CS_PIN);
}

static void Rs485RxMode(void)
{
    gpio_bit_reset(USART1_GPIO_PORT, RS485_CS_PIN);
}

static void Usart1DmaInit(void)
{
    dma_single_data_parameter_struct dma_init_para;

    rcu_periph_clock_enable(RCU_DMA0);

    dma_deinit(DMA0, DMA_CH5);
    dma_init_para.direction           = DMA_PERIPH_TO_MEMORY;
    dma_init_para.memory0_addr        = (uint32_t)usart1_rx_buffer_dma;
    dma_init_para.memory_inc          = DMA_MEMORY_INCREASE_ENABLE;
    dma_init_para.number              = USART1_BUFFER_SIZE;
    dma_init_para.periph_addr         = USART1_DATA_ADDRESS;
    dma_init_para.periph_inc          = DMA_PERIPH_INCREASE_DISABLE;
    dma_init_para.periph_memory_width = DMA_PERIPH_WIDTH_8BIT;
    dma_init_para.priority            = DMA_PRIORITY_ULTRA_HIGH;
    dma_single_data_mode_init(DMA0, DMA_CH5, &dma_init_para);

    dma_circulation_disable(DMA0, DMA_CH5);
    dma_channel_subperipheral_select(DMA0, DMA_CH5, DMA_SUBPERI4);
    dma_channel_enable(DMA0, DMA_CH5);
}

static void Usart1PeriphInit(void)
{
    rcu_periph_clock_enable(USART1_GPIO_CLK);
    rcu_periph_clock_enable(RCU_USART1);

    gpio_af_set(USART1_GPIO_PORT, GPIO_AF_7, USART1_TX_PIN);
    gpio_af_set(USART1_GPIO_PORT, GPIO_AF_7, USART1_RX_PIN);

    gpio_mode_set(USART1_GPIO_PORT, GPIO_MODE_AF, GPIO_PUPD_PULLUP, USART1_TX_PIN);
    gpio_output_options_set(USART1_GPIO_PORT, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, USART1_TX_PIN);
    gpio_mode_set(USART1_GPIO_PORT, GPIO_MODE_AF, GPIO_PUPD_PULLUP, USART1_RX_PIN);
    gpio_output_options_set(USART1_GPIO_PORT, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, USART1_RX_PIN);

    gpio_mode_set(USART1_GPIO_PORT, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, RS485_CS_PIN);
    gpio_output_options_set(USART1_GPIO_PORT, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, RS485_CS_PIN);

    usart_deinit(USART1);
    usart_baudrate_set(USART1, USART1_BAUDRATE);
    usart_transmit_config(USART1, USART_TRANSMIT_ENABLE);
    usart_receive_config(USART1, USART_RECEIVE_ENABLE);
    usart_dma_receive_config(USART1, USART_RECEIVE_DMA_ENABLE);
    usart_enable(USART1);

    Usart1DmaInit();

    nvic_irq_enable(USART1_IRQn, 0, 0);
    usart_interrupt_enable(USART1, USART_INT_IDLE);

    Rs485RxMode();
}

uint32_t Usart1Printf(const char *format, ...)
{
	char usart1_tx_buffer[USART1_BUFFER_SIZE];
	va_list arg;
	int len;

	va_start(arg, format);
	len = vsnprintf(usart1_tx_buffer, sizeof(usart1_tx_buffer), format, arg);
	va_end(arg);

    Rs485TxMode();

	for (uint16_t i = 0; i < len; i++)
    {
        usart_data_transmit(USART1, usart1_tx_buffer[i]);

        uint32_t timeout_ms = uwTick;
        while (RESET == usart_flag_get(USART1, USART_FLAG_TBE)) 
        {
            if ((uwTick - timeout_ms) > USART0_TIMEOUT_MS) 
            {
                return i;  // 返回已发送字节数
            }
        }
    }

    while(RESET == usart_flag_get(USART1, USART_FLAG_TC));

    Rs485RxMode();

	return len;
}

/* OLED */
uint8_t oled_cmd_buffer[2]  = {0x00, 0x00};  // 命令缓冲区: 控制字节 + 命令
uint8_t oled_data_buffer[2] = {0x40, 0x00};  // 数据缓冲区: 控制字节 + 数据
uint8_t oled_batch_buffer[258] = {0x40};     // 批量传输缓冲区: 控制字节 + 最多256字节数据 + 结束字节
uint16_t oled_buffer_index = 1;              // 当前缓冲区索引，初始化为1（预留控制字节位置）
uint16_t oled_buffer_threshold = 64;         // 缓冲区刷新阈值，设置为64字节

static void OledDmaInit(void)
{
    dma_single_data_parameter_struct dma_init_para;

    rcu_periph_clock_enable(RCU_DMA0);

    dma_deinit(DMA0, DMA_CH6);
    
    dma_single_data_para_struct_init(&dma_init_para);
    dma_init_para.direction           = DMA_MEMORY_TO_PERIPH;
    dma_init_para.memory0_addr        = (uint32_t)oled_data_buffer;
    dma_init_para.memory_inc          = DMA_MEMORY_INCREASE_ENABLE;
    dma_init_para.periph_memory_width = DMA_PERIPH_WIDTH_8BIT;
    dma_init_para.number              = 2;
    dma_init_para.periph_addr         = I2C0_DATA_ADDRESS;
    dma_init_para.periph_inc          = DMA_PERIPH_INCREASE_DISABLE;
    dma_init_para.priority            = DMA_PRIORITY_ULTRA_HIGH;
    dma_single_data_mode_init(DMA0, DMA_CH6, &dma_init_para);

    dma_circulation_disable(DMA0, DMA_CH6);
    dma_channel_subperipheral_select(DMA0, DMA_CH6, DMA_SUBPERI1);

    // 初始化批量传输缓冲区变量
    oled_batch_buffer[0] = 0x40;  // 设置控制字节为数据模式
    oled_buffer_index = 1;        // 重置缓冲区索引
    oled_buffer_threshold = 64;   // 设置刷新阈值
}

static void OledPeriphInit(void)
{
    rcu_periph_clock_enable(OLED_GPIO_CLK);
    rcu_periph_clock_enable(RCU_I2C0);
    
    gpio_af_set(OLED_GPIO_PORT, GPIO_AF_4, OLED_DAT_PIN);
    gpio_af_set(OLED_GPIO_PORT, GPIO_AF_4, OLED_CLK_PIN);
    
    gpio_mode_set(OLED_GPIO_PORT, GPIO_MODE_AF, GPIO_PUPD_PULLUP, OLED_DAT_PIN);
    gpio_output_options_set(OLED_GPIO_PORT, GPIO_OTYPE_OD, GPIO_OSPEED_50MHZ, OLED_DAT_PIN);
    gpio_mode_set(OLED_GPIO_PORT, GPIO_MODE_AF, GPIO_PUPD_PULLUP, OLED_CLK_PIN);
    gpio_output_options_set(OLED_GPIO_PORT, GPIO_OTYPE_OD, GPIO_OSPEED_50MHZ, OLED_CLK_PIN);
    
    i2c_clock_config(I2C0, 400000, I2C_DTCY_2);
    i2c_mode_addr_config(I2C0, I2C_I2CMODE_ENABLE, I2C_ADDFORMAT_7BITS, I2C0_OWN_ADDRESS7);
    i2c_enable(I2C0);
    i2c_ack_config(I2C0, I2C_ACK_ENABLE);
    
    OledDmaInit();

    OLED_Init();
}

int OledDrawStr(uint8_t x, uint8_t y, const char *format, ...)
{
	char buffer[512];
	va_list arg;
	int len;

	va_start(arg, format);
	len = vsnprintf(buffer, sizeof(buffer), format, arg);
	va_end(arg);

	OLED_ShowStr(x, y, buffer, 16);
	return len;
}

/* RTC */
rtc_parameter_struct ucRtc;

uint32_t prescaler_a = 0;
uint32_t prescaler_s = 0;

uint32_t rtcsrc_flag = 0;

uint8_t BcdToDec(uint8_t bcd)
{
    return ((bcd >> 4) * 10) + (bcd & 0x0F);
}

uint8_t DecToBcd(uint8_t dec)
{
    return ((dec / 10) << 4) + (dec % 10);
}

void SetRtc(rtc_parameter_struct *current_time)
{
    rtc_parameter_struct rtc_time = {0};
    
    rtc_time.year        = DecToBcd(current_time->year);
    rtc_time.month       = DecToBcd(current_time->month);
    rtc_time.date        = DecToBcd(current_time->date);
    rtc_time.day_of_week = 1;
    rtc_time.hour        = DecToBcd(current_time->hour);
    rtc_time.minute      = DecToBcd(current_time->minute);
    rtc_time.second      = DecToBcd(current_time->second);
    rtc_time.factor_asyn = prescaler_a;
    rtc_time.factor_syn  = prescaler_s;
    rtc_time.am_pm       = RTC_AM;

    if(rtc_init(&rtc_time) == ERROR)
    {
        Usart0Printf("RTC time configuration failed\r\n");
    }
}

void ReadRtc(rtc_parameter_struct *current_time)
{
    rtc_parameter_struct rtc_time = {0};

    rtc_current_time_get(&rtc_time);
    current_time->year        = BcdToDec(rtc_time.year);
    current_time->month       = BcdToDec(rtc_time.month);
    current_time->date        = BcdToDec(rtc_time.date);
    current_time->day_of_week = rtc_time.day_of_week;
    current_time->hour        = BcdToDec(rtc_time.hour);
    current_time->minute      = BcdToDec(rtc_time.minute);
    current_time->second      = BcdToDec(rtc_time.second);
    current_time->factor_asyn = rtc_time.factor_asyn;
    current_time->factor_syn  = rtc_time.factor_syn;
    current_time->am_pm       = rtc_time.am_pm;
}

static void RtcPreConfig(void)
{
    #if defined (RTC_CLOCK_SOURCE_IRC32K)
          rcu_osci_on(RCU_IRC32K);
          rcu_osci_stab_wait(RCU_IRC32K);
          rcu_rtc_clock_config(RCU_RTCSRC_IRC32K);

          prescaler_s = 0x13F;
          prescaler_a = 0x63;
    #elif defined (RTC_CLOCK_SOURCE_LXTAL)
          rcu_osci_on(RCU_LXTAL);
          rcu_osci_stab_wait(RCU_LXTAL);
          rcu_rtc_clock_config(RCU_RTCSRC_LXTAL);

          prescaler_s = 0xFF;
          prescaler_a = 0x7F;
    #else
    #error RTC clock source should be defined.
    #endif /* RTC_CLOCK_SOURCE_IRC32K */

    rcu_periph_clock_enable(RCU_RTC);
    rtc_register_sync_wait();
}

static void RtcPeriphInit(void)
{
    rcu_periph_clock_enable(RCU_PMU);
    pmu_backup_write_enable();

    RtcPreConfig();

    rtcsrc_flag = GET_BITS(RCU_BDCTL, 8, 9);

    if ((BKP_VALUE != RTC_BKP0) || (0x00 == rtcsrc_flag))
    {
        ucRtc.year = 25; ucRtc.month  = 8; ucRtc.date   = 1;
        ucRtc.hour = 0 ; ucRtc.minute = 0; ucRtc.second = 0;
        SetRtc(&ucRtc);

        RTC_BKP0 = BKP_VALUE;
        Usart0Printf("RTC initialized and backup flag set\r\n");
    }
    else
    {
        if (RESET != rcu_flag_get(RCU_FLAG_PORRST))
        {
            Usart0Printf("power on reset occurred....\n\r");
        }
        else if (RESET != rcu_flag_get(RCU_FLAG_EPRST))
        {
            Usart0Printf("external reset occurred....\n\r");
        }
        Usart0Printf("no need to configure RTC....\n\r");
    }

    rcu_all_reset_flag_clear();
}

/* FLASH */
uint8_t spi1_tx_buffer[FLASH_BUFFER_SIZE] = {0};  // SPI1 DMA Tx Buffer
uint8_t spi1_rx_buffer[FLASH_BUFFER_SIZE] = {0};  // SPI1 DMA Rx Buffer

static void FlashPeriphInit(void)
{
    spi_parameter_struct spi_init_para;

    rcu_periph_clock_enable(FLASH_GPIO_CLK);
    rcu_periph_clock_enable(RCU_SPI1);
    rcu_periph_clock_enable(RCU_DMA0);
    
    gpio_af_set(FLASH_GPIO_PORT, GPIO_AF_5, SPI1_SCK_PIN | SPI1_MISO_PIN | SPI1_MOSI_PIN);
    gpio_mode_set(FLASH_GPIO_PORT, GPIO_MODE_AF, GPIO_PUPD_NONE, SPI1_SCK_PIN | SPI1_MISO_PIN | SPI1_MOSI_PIN);
    gpio_output_options_set(FLASH_GPIO_PORT, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, SPI1_SCK_PIN | SPI1_MISO_PIN | SPI1_MOSI_PIN);

    gpio_mode_set(FLASH_GPIO_PORT, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, SPI1_NSS_PIN);
    gpio_output_options_set(FLASH_GPIO_PORT, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, SPI1_NSS_PIN);

    spi_init_para.trans_mode           = SPI_TRANSMODE_FULLDUPLEX;
    spi_init_para.device_mode          = SPI_MASTER;
    spi_init_para.frame_size           = SPI_FRAMESIZE_8BIT;
    spi_init_para.clock_polarity_phase = SPI_CK_PL_HIGH_PH_2EDGE;
    spi_init_para.nss                  = SPI_NSS_SOFT;
    spi_init_para.prescale             = SPI_PSC_8;
    spi_init_para.endian               = SPI_ENDIAN_MSB;
    spi_init(SPI1, &spi_init_para);

    spi_flash_init();
}

/* TF card */
FATFS fs;

static void TfPeriphInit(void)
{
    nvic_irq_enable(SDIO_IRQn, 0, 0);

    uint16_t retry_count = 5;
    DSTATUS disk_status = 0;
    FRESULT result = FR_OK;

    do {
        disk_status = disk_initialize(0);
    } while ((disk_status != 0) && (--retry_count));

    if (disk_status != 0)
    {
        Usart0Printf("TF card initialization failed\n");
        return;
    }

    result = f_mount(0, &fs);
    if (result != FR_OK)
    {
        Usart0Printf("File system mount failed\n");
        return;
    }
}

/* System Init */
void SysInit(void)
{
    /* SYSTICK */
    systick_config();
    /* LED */
    LedPeriphInit();
    /* BTN */
    BtnPeriphInit();
    /* ADC */
    AdcPeriphInit();
    /* USART0 */
    Usart0PeriphInit();
    /* USART1 */
    Usart1PeriphInit();
    /* OLED */
    OledPeriphInit();
    /* FLASH */
    FlashPeriphInit();
    /* RTC */
    RtcPeriphInit();
    /* TF card */
    TfPeriphInit();
}
